﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System.IO;
using System.Xml.Serialization;
using Turnota.Pathfinding;

namespace Turnota.Map
{
    public class Map
    {
        private const int MAP_WIDTH = 18;
        private const int MAP_HEIGHT = 15;
        public Tile[,] tiles = new Tile[MAP_WIDTH, MAP_HEIGHT];
        private const int TILE_WIDTH = 60;
        private const int TILE_HEIGHT = 30;
        public Point selectedTileIndex;
        private Texture2D selectorImage;
        private Texture2D mapImage;
        private Texture2D pathImage;

       
        public int Width
        {
            get { return MAP_WIDTH; }
        }

        public int Height
        {
            get { return MAP_HEIGHT; }
        }

        public Map()
        {
            selectorImage = Game1.contentManager.Load<Texture2D>("TileSelector");
            mapImage = Game1.contentManager.Load<Texture2D>("Map");

            for (int y = 0; y < MAP_HEIGHT; y++)
                for (int x = 0; x < MAP_WIDTH; x++)
                    InitializeTile(x, y, 0);

            // hardcoding a random map just because
            InitializeTile(0, 9, 5);
            InitializeTile(0, 8, 2);
            InitializeTile(0, 7, 2);
            InitializeTile(0, 6, 2);
            InitializeTile(0, 5, 2);
            InitializeTile(1, 9, 1);
            InitializeTile(1, 8, 1);
            InitializeTile(1, 7, 1);
            InitializeTile(1, 6, 1);

            InitializeTile(4, 4, -0.5f);
            InitializeTile(4, 3, -0.5f);
            InitializeTile(4, 2, -0.5f);
            InitializeTile(3, 2, -0.5f);
 
            selectedTileIndex = new Point(8, 8);

            Load();
            tiles[2, 2].Walkable = false;
            tiles[3, 2].Walkable = false;
            tiles[4, 2].Walkable = false;
            tiles[4, 3].Walkable = false;
            tiles[4, 4].Walkable = false;
            tiles[5, 4].Walkable = false;
            tiles[6, 4].Walkable = false;
            tiles[7, 4].Walkable = false;
            tiles[8, 4].Walkable = false;
            tiles[9, 4].Walkable = false;
            tiles[8, 5].Walkable = false;
            tiles[8, 6].Walkable = false;
            tiles[8, 7].Walkable = false;
            tiles[9, 5].Walkable = false;
            tiles[9, 6].Walkable = false;
            tiles[9, 7].Walkable = false;

        }

        private void InitializeTile(int x, int y, float height)
        {
            tiles[x, y] = new Tile(ConvertTileIndexToScreenPosition(x, y, height), height);
        }

        public void ModifyTileHeight(float amount)
        {
            float height = tiles[selectedTileIndex.X, selectedTileIndex.Y].Height + amount;
            InitializeTile(selectedTileIndex.X, selectedTileIndex.Y, height);
        }

        public void Save()
        {
            List<float> heights = new List<float>();
            for (int y = 0; y < MAP_HEIGHT; y++)
                for (int x = 0; x < MAP_WIDTH; x++)
                    heights.Add(tiles[x, y].Height);

            using (var stream = File.Create(@"levels\file.xml")) {
                var serializer = new XmlSerializer(typeof(float[]));
                serializer.Serialize(stream, heights.ToArray());
            }
                
        }

        public void Load()
        {
            XmlSerializer serializer = new XmlSerializer(typeof(float[]));

            StreamReader reader = new StreamReader(@"levels\file.xml");
            List<float> heights = new List<float>((float[])serializer.Deserialize(reader));
            reader.Close();
            int i = 0;

            for (int y = 0; y < MAP_HEIGHT; y++)
                for (int x = 0; x < MAP_WIDTH; x++)
                {
                    InitializeTile(x, y, heights[i]);
                    i += 1;
                }
           

        }

        public void MoveSelector(int x, int y)
        {
            Point newPoint = new Point(selectedTileIndex.X + x, selectedTileIndex.Y + y);

            if (newPoint.X >= 0 && newPoint.X < MAP_WIDTH && newPoint.Y >= 0 && newPoint.Y < MAP_HEIGHT)
                selectedTileIndex = newPoint;
        }

        public Point ConvertScreenPositionToTileIndex(Vector2 screenPosition)
        {
            float shortestDistance = int.MaxValue;
            Point nearestIndex = new Point(0, 0);

            for (int x = 0; x < MAP_WIDTH; x++)
                for (int y = 0; y < MAP_HEIGHT; y++)
                {
                    float distance = Vector2.Distance(screenPosition, tiles[x, y].CenterPosition);
                    if (distance < shortestDistance)
                    {
                        shortestDistance = distance;
                        nearestIndex = new Point(x, y);
                    }
                }

            return nearestIndex;
        }

        public void SetSelector(int x, int y)
        {
            selectedTileIndex.X = x;
            selectedTileIndex.Y = y;
        }

        public void Draw()
        {
            

            for (int x = 0; x < MAP_WIDTH; x++)
                for (int y = MAP_HEIGHT - 1; y >= 0; y--)
                    tiles[x, y].Draw();  // this is just for debugging, won't actually be drawn i don't think

            Game1.spriteBatch.Draw(mapImage, new Vector2(0, 0), null, Color.White, 0f, Vector2.Zero, 1f, SpriteEffects.None, 0.8f);

            DrawSelector();
        }

        public void DrawSelector()
        {
            Vector2 position = tiles[selectedTileIndex.X, selectedTileIndex.Y].Position;
            Game1.spriteBatch.Draw(selectorImage, position, null, Color.White, 0f, Vector2.Zero, 1f, SpriteEffects.None, 0.3f);
        }

        public void DrawPath()
        {
            Vector2 position = tiles[selectedTileIndex.X, selectedTileIndex.Y].Position;
            Game1.spriteBatch.Draw(selectorImage, position, null, Color.White, 0f, Vector2.Zero, 1f, SpriteEffects.None, 0.3f);
        }

        public Vector2 ConvertTileIndexToScreenPosition(int x, int y, float height)
        {
            int screenX = (y * TILE_WIDTH / 2) + (x * TILE_WIDTH / 2);
            int screenY = (x * TILE_HEIGHT / 2) - (y * TILE_HEIGHT / 2);
            int heightModifier = (int)(height * 10);

            return new Vector2(screenX + 20, screenY + 250 - heightModifier);
        }

    }
}
